﻿#if !NOEXPRESSION
using System;
using System.Linq.Expressions;
using MugenInjection.Infrastructure;
#endif
using MugenInjection.Delegates;
using MugenInjection.Interface;
using MugenInjection.Syntax.Constant;
using MugenInjection.Syntax.Method;
using MugenInjection.Syntax.Type;

namespace MugenInjection.Syntax
{
    /// <summary>
    /// Specific fluent syntax for create binding.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface IGenericBindingSyntax<T> : ICommonBindingSyntax
    {
        /// <summary>
        /// Indicates that the service should be self-bound.
        /// </summary>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<T> ToSelf();

        /// <summary>
        /// Indicates that the service should be bound to the specified type <see cref="T"/>.
        /// </summary>
        /// <typeparam name="TTypeTo">The specified <see cref="System.Type"/>.</typeparam>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>() where TTypeTo : T;

        /// <summary>
        /// Indicates that the service should be bound to the specified method.
        /// </summary>
        /// <typeparam name="TTypeTo">The specified <see cref="System.Type"/>.</typeparam>
        /// <param name="methodBindingDelegate">The specified <see cref="MethodBindingDelegate{TTypeTo}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectPriorityScopeUseWhenWithSyntax<TTypeTo> ToMethod<TTypeTo>(MethodBindingDelegate<TTypeTo> methodBindingDelegate) where TTypeTo : T;

        /// <summary>
        /// Indicates that the service should be bound to the specified constant value.
        /// </summary>
        /// <param name="constValue">The specified constant value.</param>
        /// <returns>The fluent syntax.</returns>
        IConstantCallbackObjectPriorityWhenSyntax<TTypeTo> ToConstant<TTypeTo>(TTypeTo constValue) where TTypeTo : T;

#if !NOEXPRESSION
        /// <summary>
        /// Adds a constructor argument for the specified argument expression.
        /// </summary>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>(Expression<Func<ResolveContext, TTypeTo>> expression, params IInjectionParameter[] parameters) where TTypeTo : T;
#endif
    }

    /// <summary>
    /// Specific fluent syntax for create binding.
    /// </summary>
    public interface IGenericBindingSyntax<in T1, in T2> : ICommonBindingSyntax
    {
        /// <summary>
        /// Indicates that the service should be bound to the specified types.
        /// </summary>
        /// <typeparam name="TTypeTo">The specified <see cref="System.Type"/>.</typeparam>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>() where TTypeTo : T1, T2;

        /// <summary>
        /// Indicates that the service should be bound to the specified method.
        /// </summary>
        /// <typeparam name="TTypeTo"></typeparam>
        /// <param name="methodBindingDelegate">The specified <see cref="MethodBindingDelegate{TTypeTo}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectPriorityScopeUseWhenWithSyntax<TTypeTo> ToMethod<TTypeTo>(MethodBindingDelegate<TTypeTo> methodBindingDelegate) where TTypeTo : T1, T2;

        /// <summary>
        /// Indicates that the service should be bound to the specified constant value.
        /// </summary>
        /// <param name="constValue">The specified constant value.</param>
        /// <returns>The fluent syntax.</returns>
        IConstantCallbackObjectPriorityWhenSyntax<TTypeTo> ToConstant<TTypeTo>(TTypeTo constValue) where TTypeTo : T1, T2;

#if !NOEXPRESSION
        /// <summary>
        /// Adds a constructor argument for the specified argument expression.
        /// </summary>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>(Expression<Func<ResolveContext, TTypeTo>> expression, params IInjectionParameter[] parameters) where TTypeTo : T1, T2;
#endif
    }

    /// <summary>
    /// Specific fluent syntax for create binding.
    /// </summary>
    public interface IGenericBindingSyntax<in T1, in T2, in T3> : ICommonBindingSyntax
    {
        /// <summary>
        /// Indicates that the service should be bound to the specified types.
        /// </summary>
        /// <typeparam name="TTypeTo">The specified <see cref="System.Type"/>.</typeparam>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>() where TTypeTo : T1, T2, T3;

        /// <summary>
        /// Indicates that the service should be bound to the specified method.
        /// </summary>
        /// <typeparam name="TTypeTo"></typeparam>
        /// <param name="methodBindingDelegate">The specified <see cref="MethodBindingDelegate{TTypeTo}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectPriorityScopeUseWhenWithSyntax<TTypeTo> ToMethod<TTypeTo>(MethodBindingDelegate<TTypeTo> methodBindingDelegate) where TTypeTo : T1, T2, T3;

        /// <summary>
        /// Indicates that the service should be bound to the specified constant value.
        /// </summary>
        /// <param name="constValue">The specified constant value.</param>
        /// <returns>The fluent syntax.</returns>
        IConstantCallbackObjectPriorityWhenSyntax<TTypeTo> ToConstant<TTypeTo>(TTypeTo constValue) where TTypeTo : T1, T2, T3;

#if !NOEXPRESSION
        /// <summary>
        /// Adds a constructor argument for the specified argument expression.
        /// </summary>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>(Expression<Func<ResolveContext, TTypeTo>> expression, params IInjectionParameter[] parameters) where TTypeTo : T1, T2, T3;
#endif
    }

    /// <summary>
    /// Specific fluent syntax for create binding.
    /// </summary>
    public interface IGenericBindingSyntax<in T1, in T2, in T3, in T4> : ICommonBindingSyntax
    {
        /// <summary>
        /// Indicates that the service should be bound to the specified types.
        /// </summary>
        /// <typeparam name="TTypeTo">The specified <see cref="System.Type"/>.</typeparam>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>() where TTypeTo : T1, T2, T3, T4;

        /// <summary>
        /// Indicates that the service should be bound to the specified method.
        /// </summary>
        /// <typeparam name="TTypeTo"></typeparam>
        /// <param name="methodBindingDelegate">The specified <see cref="MethodBindingDelegate{TTypeTo}"/>.</param>
        /// <returns>The fluent syntax.</returns>
        IMethodCallbackObjectPriorityScopeUseWhenWithSyntax<TTypeTo> ToMethod<TTypeTo>(MethodBindingDelegate<TTypeTo> methodBindingDelegate) where TTypeTo : T1, T2, T3, T4;

        /// <summary>
        /// Indicates that the service should be bound to the specified constant value.
        /// </summary>
        /// <param name="constValue">The specified constant value.</param>
        /// <returns>The fluent syntax.</returns>
        IConstantCallbackObjectPriorityWhenSyntax<TTypeTo> ToConstant<TTypeTo>(TTypeTo constValue) where TTypeTo : T1, T2, T3, T4;

#if !NOEXPRESSION
        /// <summary>
        /// Adds a constructor argument for the specified argument expression.
        /// </summary>
        /// <returns>The fluent syntax.</returns>
        ITypeCallbackConstructorObjectPriorityScopeUseWhenWithSyntax<TTypeTo> To<TTypeTo>(Expression<Func<ResolveContext, TTypeTo>> expression, params IInjectionParameter[] parameters) where TTypeTo : T1, T2, T3, T4;
#endif
    }
}
